home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Utilities / Programming / EnterAct 3.5 / hAWK project / AWK Source / CodeResource_Helper.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-24  |  24.0 KB  |  977 lines  |  [TEXT/KEEN]

  1. /* CodeResource_Helper.c - some handy functions for this and that */
  2. /* Copyright not bothered with - this is pretty standard stuff. */
  3. #include "CodeResource.h"
  4. #include <stdlib.h>
  5.  
  6. /* Resources */
  7. short OpenOrCreateResourceFork(StringPtr fileName);
  8. void DeleteAllExistingRsrcs(long theType, short theNum);
  9. /* Dialogs */
  10. void GetDlogOrigin (short dlogID, Point *where);
  11. Boolean GetAndAlignDialog(short  resID);
  12. void FrameDialogItem(DialogPtr theDP,short theItem);
  13. void SetEText(DialogPtr dPtr, short theItem, StringPtr newStr);
  14. void GetEText(DialogPtr dPtr, short theItem, StringPtr currentStr);
  15. void SetCheck(DialogPtr dPtr, short chkItem, short zeroMeansNoCheck);
  16. void GetCheck(DialogPtr dPtr, short chkItem, Boolean *trueIfChecked);
  17. Handle GetButton(DialogPtr dPtr, short btnItem);
  18. void HiliteDlgControl(DialogPtr dPtr, short btnItem, short state);
  19. /* Pascal strings */
  20. void CopyPStr(Byte *srcStr, Byte *dstStr);
  21. void AppendPStr(Byte *s1, Byte *s2);
  22. Boolean PEqualStrs(Byte *aStr, Byte *bStr);
  23. /* Files, names and locations */
  24. Byte *FullPathNameFromDirectory(long DirID, short vRefNum, Byte *s);
  25. Byte *FullPathNameFromVRefNum(short vRefNum, Byte *s);
  26. short    OpenWorkingDirectoryFromFullName(char *name, short len);
  27. /* Memory allocation */
  28. void InitTempCodeMemory(void);
  29. void *TMalloc(size_t size);
  30. void *Trealloc(void *ptr, size_t size);
  31. void Tfree(void *ptr);
  32. void TFreeAll(void);
  33. /* more memory allocation - faster, more efficient version */
  34. void *Fmalloc(register size_t nbytes);
  35. static void morecore(register short bucket);
  36. static void *true_get_memory(size_t size);
  37. void Ffree(void *cp);
  38. void *Frealloc(void *cp, size_t nbytes);
  39. static short findbucket(union overhead *freep, short srchlen);
  40. void FFreeAll(void);
  41. /* Misc */
  42. void NullOut(char *str, long nBytes);
  43. Boolean TaskWasInterrupted(void);
  44. Boolean CheckInWithCallingApp(void);
  45.  
  46. /* Resources */
  47.  
  48. /* Returns nonzero refnum if successful */
  49. short OpenOrCreateResourceFork(StringPtr fileName)
  50.     {
  51.     short refNum;
  52.     
  53.     if ((refNum = OpenResFile(fileName)) != -1 && refNum
  54.         && ResError() == noErr) /* perfect paranoia */
  55.         return(refNum);
  56.     else
  57.         {
  58.         CreateResFile(fileName);
  59.         if (ResError() != noErr)
  60.             return(0);
  61.         if ((refNum = OpenResFile(fileName)) != -1 && refNum
  62.             && ResError() == noErr)
  63.             return(refNum);
  64.         }
  65.     return(0);
  66.     }
  67.  
  68. /* Delete all instances of a particular resource.
  69. Call before creating each resource. */
  70. void DeleteAllExistingRsrcs(long theType, short theNum)
  71.     {
  72.     Handle        rsrcHdle;
  73.     
  74.     while (rsrcHdle = Get1Resource(theType, theNum))
  75.         {
  76.         RmveResource(rsrcHdle);
  77.         DisposHandle(rsrcHdle);
  78.         }
  79.     }
  80.  
  81.  
  82. /* Dialogs */
  83.  
  84. void GetDlogOrigin (short dlogID, Point *where)
  85.     {
  86.     short     screenWidth = GetScreenWidth();
  87.     short     screenHeight = GetScreenHeight();
  88.     register DialogTHndl dlogHandle;
  89.     register Rect * drp;
  90.     register short     dlogWidth, dlogHeight;
  91.  
  92.     /* Get a handle to the dialog */
  93.     dlogHandle = (DialogTHndl) GetResource ('DLOG', dlogID);
  94.  
  95.     if (!dlogHandle)
  96.         {
  97.         SetPt (where, 85, 85);
  98.         return;
  99.         }
  100.  
  101.     /* get pointer to its bounding rectangle */
  102.     drp = &((**dlogHandle).boundsRect);
  103.  
  104.     dlogWidth = drp->right - drp->left;
  105.     dlogHeight = drp->bottom - drp->top;
  106.  
  107.     /* Calculate upper left corner that will leave box centered */
  108.     where->h = (screenWidth - dlogWidth) >> 1;
  109.     where->v = (screenHeight - dlogHeight) >> 1;
  110.     }
  111.  
  112.  
  113. Boolean GetAndAlignDialog(short  resID)
  114.     {
  115.     short            sW,sH,dW,dH,left;
  116.     Rect        *drp;
  117.     DialogTHndl    dlogHandle;
  118.     Boolean        bigScreen;
  119.     
  120.     if (!GetResource('DLOG', resID)
  121.         || !GetResource('DITL', resID)
  122.         || ResError())
  123.         {
  124.         MemoryAlert();
  125.         return(FALSE);
  126.         }
  127.     sW = GetScreenWidth();
  128.     sH = GetScreenHeight();
  129.     dlogHandle = (DialogTHndl) GetResource('DLOG', resID);
  130.     drp = &((**dlogHandle).boundsRect);
  131.     dW = drp->right - drp->left;
  132.     dH = drp->bottom - drp->top;
  133.     left = (sW - dW)>>1;
  134.     /* all dialogs centered left-right */
  135.     drp->left = left;
  136.     drp->right = left + dW;
  137.     /* vertical placement depends on screen size */
  138.     if (sW >= 640 && sH >= 480)
  139.         bigScreen = TRUE;
  140.     else
  141.         bigScreen = FALSE;
  142.     
  143.     if (bigScreen)
  144.         {
  145.         /* leave one-third of white at top */
  146.         drp->top = (sH - dH) / 3;
  147.         if (drp->top < 85)
  148.             {
  149.             if (drp->top < 40)
  150.                 drp->top = 40;
  151.             if (sH <= 85 + dH)
  152.                 drp->top = 85;
  153.             }
  154.         }
  155.     else if (sH <= 85 + dH)
  156.         drp->top = 85;
  157.     else
  158.         drp->top = 40;
  159.     drp->bottom = drp->top + dH;
  160.     return(TRUE);
  161.     }
  162.  
  163. /* Place thick border around default item in a dialog */
  164. void FrameDialogItem(DialogPtr dPtr,short theItem)
  165.     {
  166.     GrafPtr            savePort;
  167.     PenState        savePen;
  168.     Handle           h;
  169.     Rect            theBox;
  170.     short                theType, ovalSize;
  171.  
  172.     GetDItem(dPtr,theItem,&theType,&h,&theBox);
  173.     GetPort(&savePort);
  174.     SetPort(dPtr);
  175.     GetPenState(&savePen);
  176.     PenNormal();
  177.     PenSize(2,2);
  178.     InsetRect(&theBox,-3,-3);
  179.     ovalSize = (theBox.bottom + 8 - theBox.top) / 2;    
  180.     FrameRoundRect(&theBox,ovalSize,ovalSize);
  181.     SetPenState(&savePen);
  182.     SetPort(savePort);
  183.     }
  184.  
  185. /* Set text content in a dialog edit field */
  186. void SetEText(DialogPtr dPtr, short theItem, StringPtr newStr)
  187.     {
  188.     short     theType;
  189.     Handle     theItemH;
  190.     Rect     theBox;
  191.  
  192.     GetDItem(dPtr, theItem, &theType, &theItemH, &theBox);
  193.     SetIText(theItemH, newStr);
  194.     }
  195.  
  196. /* Get current text in edit field - note storage for the string must
  197. be allocated by the calling function. */
  198. void GetEText(DialogPtr dPtr, short theItem, StringPtr currentStr)
  199.     {
  200.     short     theType;
  201.     Handle     theItemH;
  202.     Rect     theBox;
  203.  
  204.     GetDItem(dPtr, theItem, &theType, &theItemH, &theBox);
  205.     GetIText(theItemH, currentStr);
  206.     }
  207.  
  208. /* Set/clear check for check box or radio button, pass 0/1 or TRUE/FALSE . */
  209. void SetCheck(DialogPtr dPtr, short chkItem, short zeroMeansNoCheck)
  210.     {
  211.     short     theType;
  212.     Handle     theItemH;
  213.     Rect     theBox;
  214.  
  215.     GetDItem(dPtr, chkItem, &theType, &theItemH, &theBox);
  216.     SetCtlValue((ControlHandle)theItemH, zeroMeansNoCheck);
  217.     }
  218.  
  219. /* For check boxes and radio buttons, requires address of a Boolean from 
  220. the call as in GetCheck(dPtr, 3, &myBoolean). */
  221. /* Usage tip, to toggle a box do
  222. GetCheck (dPtr, chkItem, &myBoolean);
  223. SetCheck (dPtr, chkItem, !myBoolean);
  224. */
  225. void GetCheck(DialogPtr dPtr, short chkItem, Boolean *trueIfChecked)
  226.     {
  227.     short     theType;
  228.     Handle     theItemH;
  229.     Rect     theBox;
  230.  
  231.     GetDItem(dPtr, chkItem, &theType, &theItemH, &theBox);
  232.     *trueIfChecked = (GetCtlValue((ControlHandle)theItemH) != 0);
  233.     }
  234.  
  235. /* Retrieve ControlHandle for button, in the form of a Handle */
  236. Handle GetButton(DialogPtr dPtr, short btnItem)
  237.     {
  238.     short     theType;
  239.     Handle     theItem;
  240.     Rect     theBox;
  241.  
  242.     GetDItem(dPtr, btnItem, &theType, &theItem, &theBox);
  243.     return(theItem);
  244.     }
  245.  
  246. /* Enable (state 0) or disable (state 255) a dialog control */
  247. void HiliteDlgControl(DialogPtr dPtr, short btnItem, short state)
  248.     {
  249.     ControlHandle theButton;
  250.     
  251.     theButton = (ControlHandle) GetButton(dPtr, btnItem);
  252.     if ((**theButton).contrlHilite != state)
  253.         HiliteControl (theButton, state);
  254.     }
  255.  
  256. /* Pascal strings */
  257.  
  258. /* Copy one pascal string to another */
  259. void CopyPStr(Byte *srcStr, Byte *dstStr)
  260.     {
  261.     long   srcLen = srcStr[0];
  262.  
  263.     BlockMove(srcStr, dstStr, srcLen + 1);
  264.     }
  265.  
  266. /* Append pascal s2 to pascal s1, avoiding overflow. */
  267. void AppendPStr(Byte *s1, Byte *s2)
  268.     {
  269.     short    s1Len = s1[0];
  270.     short    s2Len = s2[0];
  271.  
  272.     if (s1Len + s2Len > 255)
  273.         s2Len = 255 - s1Len;
  274.  
  275.     if (s2Len)
  276.         {
  277.         BlockMove (s2 + 1, s1 + s1Len + 1, s2Len);
  278.         s1Len += s2Len;
  279.         s1[0] = s1Len;
  280.         }
  281.     }
  282.  
  283. Boolean PEqualStrs(Byte *aStr, Byte *bStr)
  284.     {
  285.     short i, lena = aStr[0], lenb = bStr[0];
  286.     
  287.     if (!lena || !lenb || lena != lenb)return(FALSE);
  288.     for (i = 1; i <= lena; ++i)
  289.         {
  290.         if (aStr[i] != bStr[i])
  291.             return(FALSE);
  292.         }
  293.     return(TRUE);
  294.     }
  295.  
  296. /* Files, names and locations */
  297.  
  298. /* NOTE the following two functions are based on examples supplied
  299. by Apple on one of their DTS disks - error checking has been added,
  300. and these versions are independent of the signed vs unsigned char
  301. controversy surrounding str255. Byte is defined in MacTypes.h
  302. for THINK C v4. */
  303.  
  304. /* Warning, these calls can fail! And why not? Everything else can... */
  305. /* Bug, these two are not for use by unix imitations. */
  306.  
  307. /* Construct "\PDisk:folder1:folder2:...folderN:" where folderN
  308. contains the file of interest. */
  309. Byte *FullPathNameFromDirectory(long DirID, short vRefNum, Byte *s)
  310.     {
  311.     CInfoPBRec    pb;
  312.     Byte        directoryName[256];
  313.  
  314.     s[0] = 0;
  315.     pb.dirInfo.ioNamePtr = (StringPtr)directoryName;
  316.     pb.dirInfo.ioDrParID = DirID;
  317.  
  318.     do 
  319.         {
  320.         pb.dirInfo.ioVRefNum = vRefNum;
  321.         pb.dirInfo.ioFDirIndex = -1;
  322.         pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
  323.         if (PBGetCatInfo(&pb, FALSE))
  324.             {
  325.             break;
  326.             }
  327.         /* Append a colon  */
  328.         AppendPStr(directoryName, (Byte *)"\p:");
  329.         AppendPStr(directoryName, s);
  330.         CopyPStr(directoryName, s);
  331.         } while (pb.dirInfo.ioDrDirID != 2);
  332.     return(s);
  333.     }
  334.  
  335.  
  336. Byte *FullPathNameFromVRefNum(short vRefNum, Byte *s)
  337.     {
  338.  
  339.     WDPBRec    pb;
  340.  
  341.     pb.ioNamePtr = NULL;
  342.     pb.ioVRefNum = vRefNum;
  343.     pb.ioWDIndex = 0;
  344.     pb.ioWDProcID = 0;
  345.  
  346.     if (PBGetWDInfo(&pb,false))
  347.         {
  348.         s[0] = 0;
  349.         return(s);
  350.         }
  351.     return(FullPathNameFromDirectory(pb.ioWDDirID,pb.ioWDVRefNum,s));
  352.     }
  353.  
  354. /* Determine working directory for file based on full path name. */
  355. short    OpenWorkingDirectoryFromFullName(char *name, short len)
  356.     {
  357.     WDPBRec        theParms;
  358.     OSErr     IOResult;
  359.     char volname[256];
  360.     extern void FileError(OSErr theFileErrorNum);
  361.     
  362.     volname[0] = len;
  363.     BlockMove(name, volname+1, len);
  364.     
  365.     theParms.ioCompletion = NULL;
  366.     theParms.ioVRefNum = 0;
  367.     theParms.ioNamePtr = (StringPtr)volname;
  368.     theParms.ioWDDirID = 2;
  369.     theParms.ioWDProcID = 'ERIK';
  370.     if (IOResult = PBOpenWD(&theParms, FALSE)) /* IM IV pg 158 */
  371.         {
  372.         OKStopAlert("Disk may not be on-line, \
  373. or file may have been moved, deleted, or renamed.");
  374.         theParms.ioVRefNum = 0;
  375.         }
  376.     return(theParms.ioVRefNum);
  377.     }
  378.  
  379.  
  380. /* Memory allocation */
  381. /* Preamble: at present, code resources fall into two camps; those
  382. that allocate a few chunks of memory via NewHandle, and those that
  383. allocate many chunks of memory via malloc. For the latter type,
  384. the following functions keep track of what memory was allocated,
  385. allowing it to be all freed at the end of a run with one call
  386. to TFreeAll().
  387.  
  388. To use the functions TMalloc etc  below instead of the standard malloc etc,
  389. place these lines in some header which is included in all your
  390. code resource files (see eg AWK.H), or at the top of each file:
  391.  
  392. extern void *TMalloc(size_t size);
  393. extern void *Trealloc(void *ptr, size_t size);
  394. extern void Tfree(void *ptr);
  395.  
  396. #define malloc(x) TMalloc(x)
  397. #define realloc(x, y) Trealloc(x, y)
  398. #define free(x) Tfree(x)
  399.  
  400. - before firing up your code resource, call InitTempCodeMemory()
  401.     - see eg InvokeHAWK() in hAWK_Interface.c
  402. -- and after your code resource is done, call TFreeAll()
  403.     - see eg CleanUpAfterHAWK() in hAWK_Interface.c
  404. NOTE InitTempCodeMemory() is called whether using TMalloc() etc
  405. or Fmalloc() etc, BUT the FreeAll() functions are different
  406. -TFreeAll() for the former, FFreeAll() for the latter.
  407. */
  408.  
  409.  
  410. #ifdef malloc
  411. #undef malloc
  412. #undef realloc
  413. #undef free
  414. #endif malloc
  415.  
  416. typedef struct MemoryLinks
  417.     {
  418.     struct     MemoryLinks *next, *prev;
  419.     short    flags;
  420.     }MemoryLinks;
  421.  
  422. MemoryLinks    THead;
  423. MemoryLinks *THeadPtr /* = {&THead, NULL}*/;
  424.  
  425. void InitTempCodeMemory(void)
  426.     {
  427.     THeadPtr = &THead;
  428.     THeadPtr->next = &THead;
  429.     THeadPtr->prev = &THead;
  430.     }
  431.  
  432. /* Tracking versions of malloc, realloc, free - the T stands for temp */
  433. void *TMalloc(size_t size)
  434.     {
  435.     MemoryLinks *new, *old;
  436.     
  437.     size += sizeof(MemoryLinks);
  438.     if (!(new = (MemoryLinks *)malloc(size)))
  439.         return(NULL);
  440.     old = THeadPtr->next; /* true next or THead itself */
  441.     old->prev = new;
  442.     new->next = old;
  443.     new->prev = THeadPtr;
  444.     THeadPtr->next = new;
  445.     return((void *)(new + 1)); /* user doesn't "see" the links */
  446.     }
  447.  
  448. void *Trealloc(void *ptr, size_t size)
  449.     {
  450.     MemoryLinks *retPtr;
  451.     
  452.     if (!ptr)
  453.         return(TMalloc(size));
  454.     if (!size)
  455.         {
  456.         Tfree(ptr);
  457.         return(NULL);
  458.         }
  459.     retPtr = ((MemoryLinks *)(ptr)) - 1;
  460.     /* allocate MemoryLinks, too */
  461.     size += sizeof(MemoryLinks);
  462.     retPtr = (MemoryLinks *)realloc(retPtr, size);
  463.     if (!retPtr) /* failure, but block is still there */
  464.         return(NULL);
  465.     (retPtr->prev)->next = (retPtr->next)->prev = retPtr;
  466.     return((void *)(retPtr + 1));
  467.     }
  468.  
  469. void Tfree(void *ptr)
  470.     {
  471.     MemoryLinks *out;
  472.     
  473.     if (!ptr) return;
  474.     out = ((MemoryLinks *)(ptr)) - 1;
  475.     (out->next)->prev = out->prev;
  476.     (out->prev)->next = out->next;
  477.     free(out);
  478.     }
  479.  
  480. /* list wraps around */
  481. void TFreeAll(void)
  482.     {
  483.     MemoryLinks *dump = THeadPtr->next, *nextOne;
  484. #ifdef TMEMDEBUG
  485.     long    diff;
  486.     char    numStr[16];
  487. #endif
  488.     
  489.     while (dump != THeadPtr)
  490.         {
  491.         nextOne = dump->next;
  492.         free(dump);
  493.         dump = nextOne;
  494.         }
  495. #ifdef TMEMDEBUG
  496.     NumToString(malled, (StringPtr)numStr);
  497.     PtoCstr(numStr);
  498.     OKStopAlert("Total malloc'd:");
  499.     OKStopAlert(numStr);
  500.     NumToString(realled, (StringPtr)numStr);
  501.     PtoCstr(numStr);
  502.     OKStopAlert("Total realloc'd:");
  503.     OKStopAlert(numStr);
  504.  
  505.     if (numfreedAtEnd + tfreeNum != tmallocNum)
  506.         {
  507.         diff = numfreedAtEnd + tfreeNum - tmallocNum;
  508.         if (diff < 0L)
  509.             {
  510.             diff = -diff;
  511.             NumToString(diff, (StringPtr)numStr);
  512.             PtoCstr(numStr);
  513.             OKStopAlert(numStr);
  514.             }
  515.         else /* very odd - more freed than allocated */
  516.             {
  517.             NumToString(diff, (StringPtr)numStr);
  518.             PtoCstr(numStr);
  519.             SysBeep(2);
  520.             SysBeep(2);
  521.             OKStopAlert(numStr);
  522.             }
  523.         
  524.         }
  525.     else
  526.         {
  527.         NumToString(tmallocNum, (StringPtr)numStr);
  528.         PtoCstr(numStr);
  529.         OKStopAlert("Num malloc calls total:");
  530.         OKStopAlert(numStr);
  531.         }
  532. #endif
  533.     }
  534.  
  535. /* more memory allocation - a more efficient (frugal) version */
  536.  
  537. /* A frugal malloc, especially suited for allocating many many
  538. small blocks of memory. Currently used by hAWK, which is 
  539. constantly allocating and freeing small blocks. Note TMalloc()
  540. above basically uses THINK C's malloc, which suffers from
  541. severe fragmentation problems. There is also more overhead with
  542. TMalloc (8 bytes vs 4 here).
  543. Memory is pre–allocated on demand for specific sizes only which
  544. are all powers of two (plus overhead). When you request a block
  545. of memory, your requested size is rounded up to the next power
  546. of two, and the request is satisfied from an array of similar-
  547. sized blocks. */
  548.  
  549. /* Modified for the Mac and THINK C by Ken Earle.
  550.    Based on Larry Wall’s modification (1989) of:
  551.  * malloc.c (Caltech) 2/21/82
  552.  * Chris Kingsley, kingsley@cit-20.
  553.  *
  554.  * This is a very fast storage allocator.  It allocates blocks of a small
  555.  * number of different sizes, and keeps free lists of each size.  Blocks that
  556.  * don't exactly fit are passed up to the next larger size.  In this
  557.  * implementation, the available sizes are 2^n-4 bytes long.
  558.  * This is designed for use in a program that uses vast quantities of memory,
  559.  * but bombs when it runs out.
  560.  
  561. To use the functions Fmalloc etc  below instead of the standard malloc etc,
  562. place these lines in some header which is included in all your
  563. code resource files (see eg AWK.H and CodeResHelper.h), or at 
  564. the top of each file:
  565.  
  566. extern void *Fmalloc(size_t size);
  567. extern void *Frealloc(void *ptr, size_t size);
  568. extern void Ffree(void *ptr);
  569.  
  570. #define malloc(x) Fmalloc(x)
  571. #define realloc(x, y) Frealloc(x, y)
  572. #define free(x) Ffree(x)
  573.  
  574. - before firing up your code resource, call InitTempCodeMemory()
  575.     - see eg InvokeHAWK() in hAWK_Interface.c
  576. -- and after your code resource is done, call FFreeAll()
  577.     - see eg CleanUpAfterHAWK() in hAWK_Interface.c
  578. NOTE InitTempCodeMemory() is called whether using TMalloc() etc
  579. or Fmalloc() etc, BUT the FreeAll() functions are different
  580. -TFreeAll() for the former, FFreeAll() for the latter.
  581.  */
  582.  
  583. #define u_char unsigned char
  584. #define u_int unsigned short
  585. #define u_short unsigned short
  586.  
  587. /*
  588.  * The overhead on a block is at least 4 bytes.  When free, this space
  589.  * contains a pointer to the next free block, and the bottom two bits must
  590.  * be zero.  When in use, the first byte is set to MAGIC, and the second
  591.  * byte is the size index.  The remaining bytes are for alignment.
  592.  */
  593. union    overhead {
  594.     union    overhead *ov_next;    /* when free */
  595.     struct {
  596.         u_char    ovu_magic;    /* magic number */
  597.         u_char    ovu_index;    /* bucket # */
  598.     } ovu;
  599. };
  600. #define    ov_magic    ovu.ovu_magic
  601. #define    ov_index    ovu.ovu_index
  602.  
  603. #define    MAGIC        0xff        /* magic # on accounting info */
  604.  
  605. /*
  606.  * nextf[i] is the pointer to the next free block of size 2^(i+3).  The
  607.  * smallest allocatable block is 8 bytes.  The overhead information
  608.  * precedes the data area returned to the user.
  609.  */
  610. #define    NBUCKETS 30
  611. static    union overhead *nextf[NBUCKETS];
  612.  
  613. #ifdef MSTATS
  614. /*
  615.  * nmalloc[i] is the difference between the number of mallocs and frees
  616.  * for a given block size.
  617.  */
  618. static    u_int nmalloc[NBUCKETS];
  619. #endif
  620.  
  621. /* F stands for Frugal */
  622. void *Fmalloc(register size_t nbytes)
  623.     {
  624.     union overhead *p;
  625.     short e, bucket;
  626.     
  627.     /*
  628.      * Convert amount of memory requested into
  629.      * closest block size stored in hash buckets
  630.      * which satisfies request.  Account for
  631.      * space used per block for accounting.
  632.      */
  633.     --nbytes;
  634.     if (nbytes < 1)
  635.         nbytes = 1;
  636.     e = 1;
  637.     while (nbytes >>= 1)
  638.         ++e;
  639.     if (e <= 3)
  640.         bucket = 0;
  641.     else
  642.         bucket = e - 3;
  643.     // If nothing in hash bucket right now,
  644.     // request more memory from the system.
  645.     if (nextf[bucket] == NULL)
  646.         morecore(bucket);
  647.     if ((p = (union overhead *)nextf[bucket]) == NULL)
  648.         return (NULL);
  649.     // remove from linked list
  650.     nextf[bucket] = p->ov_next;
  651.     p->ov_magic = MAGIC;
  652.     p->ov_index = bucket;
  653. #ifdef MSTATS
  654.     nmalloc[bucket]++;
  655. #endif
  656.     return ((void *)(p + 1));
  657.     }
  658.  
  659. /*
  660.  * Allocate more memory to the indicated bucket.
  661.  */
  662. static void morecore(register short bucket)
  663.     {
  664.     register union overhead *op;
  665.     register short rnu;       /* 2^rnu bytes will be requested */
  666.     register short nblks;     /* become nblks blocks of the desired size */
  667.     register short siz;
  668.  
  669.     if (nextf[bucket])
  670.         return;
  671.     if (bucket > 11)
  672.         {
  673.         nblks = 1;
  674.         rnu = bucket + 3;
  675.         }
  676.     else
  677.         {
  678.         nblks = 1 << (11 - bucket);
  679.         rnu = 14;
  680.         }
  681.     op = (union overhead *)true_get_memory((size_t)(1 << rnu)
  682.             + (size_t)(nblks) * sizeof(union overhead));
  683.     if (op == NULL)
  684.         return;
  685.     // Add new memory allocated to that on
  686.     // free list for this hash bucket.
  687.     nextf[bucket] = op;
  688.     siz = (1 << (bucket + 3)) + sizeof(union overhead);
  689.     while (--nblks > 0) {
  690.         op->ov_next = (union overhead *)((char *)op + siz);
  691.         op = (union overhead *)((char *)op + siz);
  692.     }
  693.     op->ov_next = NULL;
  694. }
  695.  
  696. /* Allocate a large lump of memory, and remember it in a linked
  697. list so that it can be disposed later.
  698. Rev Apr 95, go for tempmem (requires sys 7) before giving up. */
  699. static void *true_get_memory(size_t size)
  700.     {
  701.     MemoryLinks *new, *old;
  702.     
  703.     size += sizeof(MemoryLinks);
  704.     if (!(new = (MemoryLinks *)NewPtr((long)size)))
  705.         {
  706.         // try for tempmem before giving up
  707.         Handle    tempHandle;
  708.         OSErr    err;
  709.         
  710.         tempHandle = TempNewHandle(size, &err);
  711.         if (err == noErr)
  712.             {
  713.             HLock(tempHandle);
  714.             new = (MemoryLinks *)(*tempHandle);
  715.             new->flags = 1; // using temp mem
  716.             }
  717.         else
  718.             return(NULL);
  719.         }
  720.     else
  721.         new->flags = 0; // not using temp mem
  722.     old = THeadPtr->next; /* true next or THead itself */
  723.     old->prev = new;
  724.     new->next = old;
  725.     new->prev = THeadPtr;
  726.     THeadPtr->next = new;
  727.     return((void *)(new + 1)); /* user doesn't "see" the links */
  728.     }
  729.  
  730. void Ffree(void *cp)
  731.     {
  732.     short bucket;
  733.     union overhead *op;
  734.     
  735.     if (cp == NULL)
  736.         return;
  737.     op = (union overhead *)((char *)cp - sizeof (union overhead));
  738.     if (op->ov_magic != MAGIC) {
  739.         return;                /* sanity */
  740.     }
  741.     bucket = op->ov_index;
  742.     op->ov_next = nextf[bucket];
  743.     nextf[bucket] = op;
  744. #ifdef MSTATS
  745.     nmalloc[bucket]--;
  746. #endif
  747.     }
  748.  
  749. /*
  750.  * When a program attempts "storage compaction" as mentioned in the
  751.  * old malloc man page, it realloc's an already freed block.  Usually
  752.  * this is the last block it freed; occasionally it might be farther
  753.  * back.  We have to search all the free lists for the block in order
  754.  * to determine its bucket: 1st we make one pass thru the lists
  755.  * checking only the first block in each; if that fails we search
  756.  * ``reall_srchlen'' blocks in each list for a match (the variable
  757.  * is extern so the caller can modify it).  If that fails we just copy
  758.  * however many bytes was given to realloc() and hope it's not huge.
  759.  */
  760. short reall_srchlen = 4;    /* 4 should be plenty, -1 =>'s whole list */
  761.  
  762. void *Frealloc(void *cp, size_t nbytes)
  763.     {
  764.     register size_t onb;
  765.     union overhead *op;
  766.     char *res;
  767.     register short i;
  768.     short was_alloced = 0;
  769.  
  770.     if (cp == NULL)
  771.         return (Fmalloc(nbytes));
  772.     if (!nbytes)
  773.         {
  774.         Ffree(cp);
  775.         return(NULL);
  776.         }
  777.     op = (union overhead *)((char *)cp - sizeof (union overhead));
  778.     if (op->ov_magic == MAGIC) {
  779.         was_alloced++;
  780.         i = op->ov_index;
  781.     } else {
  782.         /*
  783.          * Already free, doing "compaction".
  784.          *
  785.          * Search for the old block of memory on the
  786.          * free list.  First, check the most common
  787.          * case (last element free'd), then (this failing)
  788.          * the last ``reall_srchlen'' items free'd.
  789.          * If all lookups fail, then assume the size of
  790.          * the memory block being realloc'd is the
  791.          * smallest possible.
  792.          */
  793.         if ((i = findbucket(op, 1)) < 0 &&
  794.             (i = findbucket(op, reall_srchlen)) < 0)
  795.             i = 0;
  796.     }
  797.     onb = (1 << (i + 3));
  798.     /* avoid the copy if same size block */
  799.     if (was_alloced &&
  800.         nbytes <= onb && nbytes > (onb >> 1) ) {
  801.         return(cp);
  802.     }
  803.     if ((res = Fmalloc(nbytes)) == NULL)
  804.         return (NULL);
  805.     if (cp != res)            /* common optimization */
  806.         BlockMove ((Ptr)cp, (Ptr)res, (Size)((nbytes < onb) ? nbytes : onb));
  807.     if (was_alloced)
  808.         Ffree(cp);
  809.     return (res);
  810. }
  811.  
  812. /*
  813.  * Search ``srchlen'' elements of each free list for a block whose
  814.  * header starts at ``freep''.  If srchlen is -1 search the whole list.
  815.  * Return bucket number, or -1 if not found.
  816.  */
  817. static short findbucket(union overhead *freep, short srchlen)
  818.     {
  819.     register union overhead *p;
  820.     register short i, j;
  821.  
  822.     for (i = 0; i < NBUCKETS; i++) {
  823.         j = 0;
  824.         for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
  825.             if (p == freep)
  826.                 return (i);
  827.             j++;
  828.         }
  829.     }
  830.     return (-1);
  831.     }
  832.  
  833. #ifdef MSTATS
  834. /*
  835.  * mstats - print out statistics about malloc
  836.  *
  837.  * Prints two lines of numbers, one showing the length of the free list
  838.  * for each size category, the second showing the number of mallocs -
  839.  * frees for each size category.
  840.  */
  841. void mstats(char *s);
  842. void mstats(char *s)
  843.     {
  844.     register short i, j;
  845.     register union overhead *p;
  846.     short totfree = 0,
  847.     totused = 0;
  848.  
  849.     fprintf(stderr, "Memory allocation statistics %s\nfree:\t", s);
  850.     for (i = 0; i < NBUCKETS; i++) {
  851.         for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
  852.             ;
  853.         fprintf(stderr, " %d", j);
  854.         totfree += j * (1 << (i + 3));
  855.     }
  856.     fprintf(stderr, "\nused:\t");
  857.     for (i = 0; i < NBUCKETS; i++) {
  858.         fprintf(stderr, " %d", nmalloc[i]);
  859.         totused += nmalloc[i] * (1 << (i + 3));
  860.     }
  861.     fprintf(stderr, "\n\tTotal in use: %d, total free: %d\n",
  862.         totused, totfree);
  863.     }
  864. #endif
  865.  
  866. /* list wraps around */
  867. void FFreeAll(void)
  868.     {
  869.     MemoryLinks *dump = THeadPtr->next, *nextOne;
  870.     Handle        tempHandle;
  871.     
  872.     while (dump != THeadPtr)
  873.         {
  874.         nextOne = dump->next;
  875.         //dump->flags = 1 means using temp mem
  876.         if (dump->flags & 1)
  877.             {
  878.             tempHandle = RecoverHandle((Ptr)dump);
  879.             if (MemError() == noErr)
  880.                 DisposeHandle(tempHandle);
  881.             }
  882.         else // just a regular pointer
  883.             DisposePtr((Ptr)dump);
  884.         dump = nextOne;
  885.         }
  886.     }
  887.  
  888.  
  889. /* Misc */
  890.  
  891. void NullOut(char *str, long nBytes)
  892.     {
  893.     register long i;
  894.     
  895.     i = nBytes;
  896.     while (--i >= 0)
  897.         *str++ = '\0';
  898.     }
  899.  
  900. /* Check for the generic "Command<period>" that signals a
  901. wish to stop. */
  902. Boolean TaskWasInterrupted()
  903.     {
  904.     EventRecord    event;
  905.     long        thisTime;
  906.     Boolean        gotEvent;
  907.     static long    lastTime;
  908.     
  909.     Delay(0L, &thisTime);
  910.     if (thisTime - lastTime < 60L) return(FALSE);
  911.     lastTime = thisTime;
  912.     SystemTask();
  913.     gotEvent = GetNextEvent(62, &event);
  914.     if (gotEvent) /* see if interrupt */
  915.         {
  916.         switch (event.what)
  917.             {
  918.         case keyDown:
  919.         case autoKey:
  920.             /* look for abort key (Command-<period>) */
  921.         if ((event.modifiers & cmdKey)
  922.              && ((event.message & charCodeMask) == '.'))
  923.             {
  924.             return(TRUE);
  925.             }
  926.         break;
  927.         default:
  928.         break;
  929.             } /* switch */
  930.         }
  931.     return(FALSE);
  932.     }
  933.  
  934. /* Check for events 15 times a second, allow hAWK to run for
  935. at most 12 ticks if no event. Return control to calling
  936. app's event loop, so that hAWK can run at the same time
  937. as calling app without too much slowdown. Return TRUE
  938. if interrupted, FALSE if should continue. */
  939. Boolean CheckInWithCallingApp()
  940.     {
  941.     EventRecord    event;
  942.     long        thisTime;
  943.     Boolean        gotEvent;
  944.     static long    lastTime, tickAlong;
  945.     
  946.     Delay(0L, &thisTime);
  947.     if (thisTime < tickAlong) return(FALSE);
  948.     tickAlong = thisTime + 4L;
  949.     
  950.     if ((gotEvent = EventAvail(everyEvent, &event))
  951.         || thisTime - lastTime > 12L)
  952.         {
  953.         if (gotEvent)
  954.             {
  955.             switch (event.what)
  956.                 {
  957.             case keyDown:
  958.             case autoKey:
  959.                 /* look for abort key (Command-<period>) */
  960.             if ((event.modifiers & cmdKey)
  961.                  && ((event.message & charCodeMask) == '.'))
  962.                 {
  963.                 GetNextEvent(62, &event);
  964.                 return(TRUE);
  965.                 }
  966.             break;
  967.             default:
  968.             break;
  969.                 } /* switch */
  970.             }
  971.         else
  972.             lastTime = thisTime;
  973.         DoEventLoopOnce();
  974.         }
  975.     return(FALSE);
  976.     }
  977.